﻿/* Nibiru Studio Engine Version [1062] */
#include "SceneCalib.h"
#include "EyeManager.h"
#include "PosUtil.h"


ENGINE_NAMESPACE_BEGIN

IMPLEMENT_CLASS(SceneCalib)
IMPLEMENT_RTTI_CUSTOM(SceneCalib, NComponent)

//ENUM_BEGIN(LabelType, LabelType)
// add your enum
// Display Name, Enum Type Name
// ENUM(Left, LEFT)
//ENUM_END


REFLECTION_BEGIN(SceneCalib)
// add your variable reflection property
//Enum Class Name, Display Name In Editor, Variable Name In Class, flags default is 0
//ENUM_PROPERTY(LabelType, Type, m_LabelType, 0)
//PROPERTY(Bold, m_IsBold, 0)
//PROPERTY(Rotate, m_EnableRotate, 0)
//FUNCTION(OnButtonClick, SceneCalib, OnClick)

REFLECTION_END


void SceneCalib::Start()
{
    m_pEyeManager = EyeManager::instance();
    m_textMessage = NActorManager::GetActor("text_message")->GetComponent<NLabel>();
    // pupil view
    m_panelLeftPupil = NActorManager::GetActor("panel_left_pupil");
    m_panelRightPupil = NActorManager::GetActor("panel_right_pupil");
    m_imgLeftPupil = NActorManager::GetActor("img_left_pupil");
    m_imgRightPupil = NActorManager::GetActor("img_right_pupil");
    m_panelLeftPupil->SetLocalPosition(Vector3(-0.5, 0.3, 0));
    m_panelRightPupil->SetLocalPosition(Vector3(0.5, 0.3, 0));
    // pupil param
    Vector2 panelPupilSize = m_panelLeftPupil->GetComponent<NPanel>()->GetSize();
    m_panelPupilWidth = panelPupilSize.x;
    m_panelPupilHeight = panelPupilSize.y;
    m_pupilValidCount = 0;
    // calibration view
    m_panelCalib = NActorManager::GetActor("canvas_calib");
    m_calibPoint = NActorManager::GetActor("img_calib_point");
    m_calibPointList.clear();
    if (7 == m_caliTotalNum)
    {
        m_calibPointList.push_back(NActorManager::GetActor("img_calib1"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib6"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib8"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib5"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib3"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib9"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib2"));

    }
    else
    {
     
        m_calibPointList.push_back(NActorManager::GetActor("img_calib1"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib2"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib3"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib4"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib5"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib6"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib7"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib8"));
        m_calibPointList.push_back(NActorManager::GetActor("img_calib9"));
    }
    

    hideCalibView();
    // calibration param
    Vector2 calibSize = m_panelCalib->GetComponent<NCanvas>()->GetSize();
    m_panelCalibWidth = calibSize.x / 2.0f;
    m_panelCalibHeight = calibSize.y / 2.0f;
}

void SceneCalib::Update()
{
    if (NInput::GetKeyDown(KeyboardKeys::Android_DpadLeft)) // 左键
    {
        NDebug::Log("%s android left", EYE_TAG);
    }
    else if (NInput::GetKeyDown(KeyboardKeys::Android_DpadRight)) // 右键进入靶盘界面
    {
        switchToTarget();
    }
    else if (NInput::GetKeyDown(KeyboardKeys::Android_DpadDown)) // 下键强制开始校准
    {
        startCalibration();
    }
    else if (NInput::GetKeyDown(KeyboardKeys::Android_DpadUp)) // 上键进入采图界面
    {
        switchToCapture();
    }
    else if (NInput::GetKeyDown(KeyboardKeys::Android_Back)) // 返回键退出程序
    {
        doStop();
    }
    updateEyeData();
    updateCalibScale();
    updateCalibPos();
    getCalibPercent();
}

void SceneCalib::OnDestroy()
{

}

void SceneCalib::PostEditChangeProperty(std::string& propertyName)
{
    // Variable Property changed in Editor
}

void SceneCalib::Serialize(Archive& ar)
{
    Super::Serialize(ar);
    // SERIALIZE(m_EnableRotate);
}

void SceneCalib::LateDeserialize(Archive& ar)
{
    // After all Serialize are executed
    Super::LateDeserialize(ar);
}

void SceneCalib::updateEyeData()
{
    EyeDataBasic eyeDataBasic;
    ServiceResult serviceResult = m_pEyeManager->getEyeData(eyeDataBasic);
    if (serviceResult.code != 0)
    {
        //NDebug::Log("%s getEyeData error, %s", EYE_TAG, serviceResult.toString().c_str());
        //m_textMessage->SetText(serviceResult.toString());
        return;
    }
    //m_textMessage->SetText("");
    // pupil
    if (m_imgLeftPupil->IsActiveSelf() && m_imgRightPupil->IsActiveSelf())
    {
        float leftPupilX = eyeDataBasic.leftPupilX;
        float leftPupilY = eyeDataBasic.leftPupilY;
        pair<float, float> srcPos(leftPupilX, leftPupilY);
        pair<float, float> destPos;
        PosUtil::normalToCenter(srcPos, m_panelPupilWidth, m_panelPupilHeight, destPos);
        m_imgLeftPupil->SetLocalPosition(Vector3(destPos.first, destPos.second, 0));

        float rightPupilX = eyeDataBasic.rightPupilX;
        float rightPupilY = eyeDataBasic.rightPupilY;
        srcPos = pair<float, float>(rightPupilX, rightPupilY);
        PosUtil::normalToCenter(srcPos, m_panelPupilWidth, m_panelPupilHeight, destPos);
        m_imgRightPupil->SetLocalPosition(Vector3(destPos.first, destPos.second, 0));

        // 有效瞳孔数据 不自动进入校准界面
        //if (m_pupilValidCount < 0)
        //{
        //    return;
        //}
        //bool leftPupilValid = (leftPupilX >= 0.25f && leftPupilX <= 0.8f && leftPupilY >= 0.25f && leftPupilY <= 0.8f);
        ////NDebug::Log("%s left x=%f, y=%f, valid=%d", EYE_TAG, leftPupilX, leftPupilY, leftPupilValid);
        //bool rightPupilValid = (rightPupilX >= 0.25f && rightPupilX <= 0.8f && rightPupilY >= 0.25f && rightPupilY <= 0.8f);
        ////NDebug::Log("%s right x=%f, y=%f, valid=%d, count=%d", EYE_TAG, rightPupilX, rightPupilY, rightPupilValid, m_pupilValidCount);
        //if (leftPupilValid && rightPupilValid)
        //{
        //    m_pupilValidCount++;
        //    if (m_pupilValidCount >= 120) // 2s
        //    {
        //        m_pupilValidCount = -1;
        //        startCalibration();
        //    }
        //}
        //else
        //{
        //    m_pupilValidCount = 0;
        //}
    }
}

void SceneCalib::doStop()
{
    NDebug::Log("%s doStop quit", EYE_TAG);
    m_pEyeManager->stop();
    NApplication::Quit();
}

void SceneCalib::startCalibration()
{
    m_panelLeftPupil->SetLocalPosition(Vector3(-0.5, -1.9, 0));
    m_panelRightPupil->SetLocalPosition(Vector3(0.5, -1.9, 0));
    m_textMessage->SetText("Follow...");

    NDebug::Log("%s startCalibration w=%f, h=%f, calibPointCount=%d", EYE_TAG, m_panelCalibWidth, m_panelCalibHeight, m_calibPointCount);
    ServiceResult serviceResult = m_pEyeManager->startCalibration(-m_panelCalibWidth, m_panelCalibWidth,
        -m_panelCalibHeight-m_offsetY, m_panelCalibHeight-m_offsetY, m_calibPointCount);
    if (serviceResult.code != 0)
    {
        NDebug::Log("%s startCalibration error, %s", EYE_TAG, serviceResult.toString().c_str());
        m_textMessage->SetText(serviceResult.toString());
        return;
    }
    int m_calibIndex = 0;
    Vector3 calibPoint0Pos = m_calibPointList.at(0)->GetLocalPosition(); // 获取第0个点的位置
    m_calibPoint->SetLocalPosition(Vector3(calibPoint0Pos.x, calibPoint0Pos.y, calibPoint0Pos.z));
    showCalibView();
    prepareStartCalib();
}

void SceneCalib::startCalibrationPoint()
{
    Vector3 calibPos = m_calibPoint->GetLocalPosition();
    calibPos.y -= m_offsetY;
    NDebug::Log("%s startCalibrationPoint index=%d, x=%f, y=%f,offsetY=%f", EYE_TAG, m_calibIndex + 1, calibPos.x, calibPos.y,m_offsetY);
    ServiceResult serviceResult = m_pEyeManager->startCalibrationPoint(m_calibIndex + 1,
        calibPos.x, calibPos.y, calibPos.x, calibPos.y);
    if (serviceResult.code != 0)
    {
        NDebug::Log("%s startCalibrationPoint error, %s", EYE_TAG, serviceResult.toString().c_str());
        m_textMessage->SetText(serviceResult.toString());
        return;
    }
    m_textMessage->SetText("");
    m_calibPercentCount = 10;
    m_calibPercentValid = true;
}

void SceneCalib::cancelCalibrationPoint()
{
    m_calibPosValid = false;
    m_calibPercentValid = false;
    NDebug::Log("%s cancelCalibrationPoint", EYE_TAG);
    ServiceResult serviceResult = m_pEyeManager->cancelCalibrationPoint();
    if (serviceResult.code != 0)
    {
        NDebug::Log("%s cancelCalibrationPoint error, %s", EYE_TAG, serviceResult.toString().c_str());
        m_textMessage->SetText(serviceResult.toString());
        return;
    }
}

void SceneCalib::completeCalibration()
{
    m_calibPosValid = false;
    m_calibPercentValid = false;
    NDebug::Log("%s completeCalibration", EYE_TAG);
    ServiceResult serviceResult = m_pEyeManager->completeCalibration();
    if (serviceResult.code != 0)
    {
        NDebug::Log("%s completeCalibration error, %s", EYE_TAG, serviceResult.toString().c_str());
        m_textMessage->SetText(serviceResult.toString());
        return;
    }
    switchToTarget();
}

void SceneCalib::prepareStartCalib()
{
    if (m_calibIndex >= m_calibPointCount)
    {
        completeCalibration();
        return;
    }
    NActorPtr curPoint = m_calibPointList.at(m_calibIndex); // 获取下一个校准点的位置
    m_calibPoint->SetScale(1);
    m_calibLastX = m_calibPoint->GetLocalPosition().x;
    m_calibLastY = m_calibPoint->GetLocalPosition().y;
    m_calibPosDX = curPoint->GetLocalPosition().x - m_calibLastX;
    m_calibPosDY = curPoint->GetLocalPosition().y - m_calibLastY;
    m_calibPosValid = true;

    if (abs(m_calibPosDX) <= 0.001 && abs(m_calibPosDY) <= 0.001)
    {
        m_calibPosRatio = 1;
    }
    else
    {
        m_calibPosRatio = 0;
    }
}

void SceneCalib::showCalibView()
{
    /*for (auto calibPoint : m_calibPointList)
    {
        calibPoint->SetScale(1);
        calibPoint->SetActive(true);
    }*/
    m_calibPoint->SetScale(1);
    m_calibPoint->SetActive(true);
}

void SceneCalib::hideCalibView()
{
    m_calibPoint->SetActive(false);
    m_calibPoint->SetScale(1);
}

void SceneCalib::updateCalibPos()
{
    if (!m_calibPosValid)
    {
        return;
    }
    if (m_calibIndex == 0)
    {
        m_calibPosValid = false;
        m_calibScale = 1;
        m_calibScaleValid = true;
        return;
    }

    m_calibPosRatio += 0.03f;
    if (m_calibPosRatio >= 1)
    {
        m_calibPoint->SetLocalPosition(Vector3(m_calibLastX + m_calibPosDX, m_calibLastY+m_calibPosDY, 0));
        m_calibPosValid = false;
        m_calibScale = 1;
        m_calibScaleValid = true;
        return;
    }
    m_calibPoint->SetLocalPosition(Vector3(m_calibLastX + m_calibPosDX* m_calibPosRatio,
        m_calibLastY + m_calibPosDY* m_calibPosRatio, 0));
}

void SceneCalib::updateCalibScale()
{
    if (!m_calibScaleValid)
    {
        return;
    }
    m_calibScale -= 0.01f;
    m_calibPoint->SetScale(m_calibScale);
    if (m_calibScale < 0.3f)
    {
        m_calibScaleValid = false;
        startCalibrationPoint();
    }
}

void SceneCalib::getCalibPercent()
{
    if (!m_calibPercentValid)
    {
        return;
    }
    int percent = m_pEyeManager->getCalibPercent();
    if (percent < 100)
    {
        m_calibPercentCount++;
        if (m_calibPercentCount >= 8)
        {
            m_calibPercentCount = 0;
            NDebug::Log("%s calib index=%d, percent=%d", EYE_TAG, m_calibIndex, percent);
        }
        return;
    }
    m_calibPercentValid = false;
    int finishCode = m_pEyeManager->getCalibFinishCode();
    if (finishCode == 0)
    {
        m_calibIndex++;
        prepareStartCalib();
        return;
    }
    if (finishCode == -2) // 手动取消校准
    {
        hideCalibView();
        m_pupilValidCount = 0;
    }
    else
    {
        string msg = "getCalibFinishCode error, code=" + to_string(finishCode);
        NDebug::Log("%s %s", EYE_TAG, msg.c_str());
        m_textMessage->SetText(msg);
        prepareStartCalib();
    }
}

void SceneCalib::switchToTarget()
{
    NLevelManager::LoadLevel("scene_target.nscene");
}

void SceneCalib::switchToCapture()
{
    NLevelManager::LoadLevel("scene_capture.nscene");
}



ENGINE_NAMESPACE_END
